/*
*
* ████████╗░█████╗░███████╗██████╗░░█████╗░
* ╚══██╔══╝██╔══██╗██╔════╝██╔══██╗██╔══██╗
* ░░░██║░░░██║░░██║█████╗░░██████╦╝███████║
* ░░░██║░░░██║░░██║██╔══╝░░██╔══██╗██╔══██║
* ░░░██║░░░╚█████╔╝██║░░░░░██████╦╝██║░░██║
* ░░░╚═╝░░░░╚════╝░╚═╝░░░░░╚═════╝░╚═╝░░╚═╝
* 
*  :: 九方通逊-Henry ::   Copyright©2020 tofba.com  
* 
*/
package com.lmexpress.service.impl;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.lmexpress.enums.ApiCredential;
import com.lmexpress.enums.ApiOrderError;
import com.lmexpress.enums.LabelSuffix;
import com.lmexpress.orm.openapi.ExpressOrderApi;
import com.lmexpress.orm.openapi.OrderInvoice;
import com.lmexpress.orm.owdiex.Order;
import com.lmexpress.orm.owdiex.Others;
import com.lmexpress.orm.owdiex.Receiver;
import com.lmexpress.orm.owdiex.Sender;
import com.lmexpress.orm.rest.ApiLabelResponse;
import com.lmexpress.orm.rest.ApiOrderResponse;
import com.lmexpress.service.ApiService;
import com.lmexpress.util.ApiUtil;
import com.lmexpress.util.HttpClientPoolUtil;
import com.lmexpress.util.HttpClientResult;
import com.lmexpress.util.MD5;
import com.lmexpress.util.PropertiesUtil;

/**
 * 
 * <星期日FBC>
 * 
 * @author Henry(fba02)
 * @version [版本号, 2020-12-09]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public class OwdiexClient implements ApiService {
	private final static Logger LOGGER = LoggerFactory.getLogger(OwdiexClient.class);
	private final static String DETAIL = "http://api.owdiex.com/gateway/api/v1/labels/detail";
	private final static String CREATE = "http://api.owdiex.com/gateway/api/v1/comparison/create";
	private final static String PRINT = "http://api.owdiex.com/gateway/api/v1/comparison/print";

	@Override
	public ApiOrderResponse preProcessCreateOrder(ExpressOrderApi expressOrderApi) {
		return null;
	}

	@Override
	public String mapping(ExpressOrderApi expressOrderApi) {
		Map<String, String> apiCredentials = expressOrderApi.getApiCredentials();
		Order order = new Order();
		Sender sender = new Sender();
		if (DEFAULT_SHIPPER.equals(apiCredentials.get(ApiCredential.OWDIEX_DEFAULT_SHIPPER.getKey()))) {
			sender.setFirstname(PropertiesUtil.getProperty("lm.shipper.name"));
			sender.setCompany(PropertiesUtil.getProperty("lm.shipper.company"));
			sender.setCountry(PropertiesUtil.getProperty("lm.shipper.country"));
			sender.setAddress_line1(PropertiesUtil.getProperty("lm.shipper.address1"));
			sender.setAddress_line2(PropertiesUtil.getProperty("lm.shipper.address2"));
			sender.setState(PropertiesUtil.getProperty("lm.shipper.province"));
			sender.setCity(PropertiesUtil.getProperty("lm.shipper.city"));
			sender.setZipcode(PropertiesUtil.getProperty("lm.shipper.zipcode"));
			sender.setMobile(PropertiesUtil.getProperty("lm.shipper.mobile"));
		} else {
			sender.setFirstname(expressOrderApi.getShipperName());
			String company = StringUtils.isBlank(expressOrderApi.getShipperCompanyName()) ? expressOrderApi.getShipperName() : expressOrderApi.getShipperCompanyName();
			sender.setCompany(company);
			sender.setCountry(expressOrderApi.getShipperCountry());
			sender.setAddress_line1(expressOrderApi.getShipperAddress1());
			sender.setState(expressOrderApi.getShipperState());
			sender.setCity(expressOrderApi.getShipperCity());
			sender.setZipcode(expressOrderApi.getShipperPostCode());
			sender.setMobile(expressOrderApi.getShipperTelephone());
		}
		order.setSender(sender);
		Receiver receiver = new Receiver();
		receiver.setFirstname(expressOrderApi.getConsigneeName());
		receiver.setCountry(expressOrderApi.getCountryCode());
		String consigneeAddress = expressOrderApi.getConsigneeAddress();
		if (null != consigneeAddress) {
			consigneeAddress = consigneeAddress.replaceAll("，", " ");
			if (consigneeAddress.length() > 30) {
				receiver.setAddress_line1(consigneeAddress.substring(0, 30));
				receiver.setAddress_line2(consigneeAddress.substring(30, consigneeAddress.length()));
			} else {
				receiver.setAddress_line1(consigneeAddress);
			}
		}
		receiver.setState(expressOrderApi.getConsigneeState());
		receiver.setCity(expressOrderApi.getConsigneeCity());
		receiver.setZipcode(expressOrderApi.getConsigneePostCode());
		String phone = StringUtils.isBlank(expressOrderApi.getConsigneeMobile()) ? expressOrderApi.getConsigneeTelephone() : expressOrderApi.getConsigneeMobile();
		receiver.setMobile(phone);
		order.setReceiver(receiver);
		Others others = new Others();
		others.setSignature_service("0");
		others.setLabel_size("1");
		others.setMailing_date(null);
		others.setPackaging_type("YOUR_PACKAGING");
		others.setSimple_label("0");// 是否返回面单信息，1：不返回，0：返回
		order.setOthers(others);
		com.lmexpress.orm.owdiex.Package package1 = new com.lmexpress.orm.owdiex.Package();
		List<OrderInvoice> orderInvoices = expressOrderApi.getOrderInvoices();
		if (CollectionUtils.isNotEmpty(orderInvoices)) {
			List<String> goodsDescs = new ArrayList<String>();
			List<String> descs = new ArrayList<String>();
			Double totalWeight = 0D;
			String sku = "";
			Double totalDeclaration = 0D;
			for (OrderInvoice orderInvoice : orderInvoices) {
				totalWeight += orderInvoice.getInvoiceWeight() == null ? 0D : orderInvoice.getInvoiceWeight();
				goodsDescs.add(orderInvoice.getSkuNameCn());
				descs.add(orderInvoice.getSkuNameEn());
				sku += orderInvoice.getSkuCode() + ",";
				totalDeclaration += orderInvoice.getInvoiceAmount() == null ? 0D : orderInvoice.getInvoiceAmount();
			}
			package1.setGoods_description(goodsDescs);
			package1.setOrder_code(expressOrderApi.getCustomerInvoiceCode());
			if (StringUtils.isNotBlank(sku)) {
				package1.setContent(sku.substring(0, sku.length() - 1));
			}
			package1.setGoods_description_en(descs);
			package1.setValue_declaration(totalDeclaration.toString());
			if (null == expressOrderApi.getWeight()) {
				expressOrderApi.setWeight(totalWeight);
			}
			Double lbsDouble = expressOrderApi.getWeight() * 2.2046;
			package1.setWeight_report(lbsDouble.toString());
			package1.setLength_report("4");
			package1.setWidth_report("4");
			package1.setHeight_report("4");
		}
		List<com.lmexpress.orm.owdiex.Package> packages = new ArrayList<com.lmexpress.orm.owdiex.Package>();
		packages.add(package1);
		order.setPackages(packages);
		Gson gson = new GsonBuilder().create();
		return gson.toJson(order);
	}

	@Override
	public ApiOrderResponse createOrder(ExpressOrderApi expressOrderApi) {
		String orderJson = mapping(expressOrderApi);
		Map<String, String> apiCredentials = expressOrderApi.getApiCredentials();
		String appKey = apiCredentials.get(ApiCredential.OWDIEX_APP_KEY.getKey());
		String appSecret = apiCredentials.get(ApiCredential.OWDIEX_APP_SECRET.getKey());
		LOGGER.info("owdiex.shipment.request.json:{}", orderJson);
		try {
			String signBody = "appkey=" + appKey + "&data=" + orderJson + "&express_company=USPSL&service_type=StandardService" + appSecret;
			String sign = new MD5(signBody).toMD5();
			LOGGER.info("owdiex.shipment.request.sign:{}", sign);
			Map<String, String> headers = new HashMap<String, String>();
			headers.put("Content-Type", "application/x-www-form-urlencoded");
			Map<String, String> params = new LinkedHashMap<String, String>();
			params.put("appkey", appKey);
			params.put("data", orderJson);
			params.put("express_company", "USPSL");
			params.put("service_type", "StandardService");
			params.put("sign", sign);
			HttpClientResult httpClientResult = HttpClientPoolUtil.doPost(CREATE, headers, params, false);
			if (null == httpClientResult) {
				return new ApiOrderResponse(false, null, ApiOrderError.SERVICE_NO_DATA_RETURN.getMessage(), true, null);
			}
			String responseJson = httpClientResult.getContent();
			if (StringUtils.isBlank(responseJson)) {
				return new ApiOrderResponse(false, null, ApiOrderError.SERVICE_NO_DATA_RETURN.getMessage(), true, null);
			}
			LOGGER.info("owdiex.shipment.response.json:{}", responseJson);
			Map<String, Object> resultMap = new Gson().fromJson(responseJson, new TypeToken<Map<String, Object>>() {
			}.getType());
			Integer code = Double.valueOf(resultMap.get("code").toString()).intValue();
			if (code == 0) {
				@SuppressWarnings("unchecked")
				Map<String, Object> dataMap = (Map<String, Object>) resultMap.get("data");
				String label_code = (String) dataMap.get("label_code");
				ApiOrderResponse apiOrderResponse = new ApiOrderResponse();// 回传数据
				apiOrderResponse.setSuccess(Boolean.valueOf(true));
				String tackNumber = detail(label_code, appKey, appSecret);
				apiOrderResponse.setTrackNumber(tackNumber);
				apiOrderResponse.setThirdPartyorderNo(label_code);
				ApiLabelResponse apiLabelResponse = label(tackNumber, expressOrderApi.getCustomerInvoiceCode(), apiCredentials);
				if (null != apiLabelResponse) {
					apiOrderResponse.setLabelUrl(apiLabelResponse.getLabelPath());// 远端地址
					apiOrderResponse.setLmLabelUrl(apiLabelResponse.getLabelPath());// 本地地址
				}
				apiOrderResponse.setOriginalResponse(responseJson);// 原始参数
				return apiOrderResponse;
			} else if (code == 200) {
				return new ApiOrderResponse(false, null, resultMap.get("msg").toString(), true, null);
			} else {
				@SuppressWarnings("unchecked")
				Map<String, Object> contentMap = (Map<String, Object>) resultMap.get("content");
				if (null == contentMap) {
					return new ApiOrderResponse(false, null, responseJson, true, null);
				} else {
					return new ApiOrderResponse(false, null, contentMap.get("msg").toString(), true, null);
				}
			}
		} catch (Exception e) {
			LOGGER.error("owdiex.shipment.exception:", e);
			return new ApiOrderResponse(false, null, ApiOrderError.CREATE_ORDER_EXCEPTION.getMessage(), true, null);
		}
	}

	public String detail(String labelCode, String appKey, String appSecret) {
		String signBody = "appkey=" + appKey + "&label_code=" + labelCode + appSecret;
		String sign = new MD5(signBody).toMD5();
		LOGGER.info("owdiex.detail.request.sign:{}", sign);
		Map<String, String> headers = new HashMap<String, String>();
		headers.put("Content-Type", "application/x-www-form-urlencoded");
		Map<String, String> params = new LinkedHashMap<String, String>();
		params.put("appkey", appKey);
		// params.put("appSecret", APP_SECRET);
		params.put("label_code", labelCode);
		params.put("sign", sign);
		try {
			HttpClientResult httpClientResult = HttpClientPoolUtil.doPost(DETAIL, headers, params, false);
			// {"code":0,"msg":"OK","data":{"id":2957423,"label_code":"LBX07252957423","17track_code":"EZEBX7252957423YQ","booking_time":"1606217925","created":"1606217925","sender_firstname":"Hnery","sender_lastname":"","sender_mobile":"13266829617","sender_company":"imc","sender_country":"CN","sender_state":"GD","sender_city":"Shenzhen","sender_address_line1":"GD
			// Shenzhen Baoan No.4 Hengnan Road Bao'an District
			// ShenzhenLIWEI","sender_address_line2":null,"sender_zipcode":"518000","receiver_firstname":"Dustin","receiver_lastname":"Stahlecker","receiver_mobile":"7193420402","receiver_company":"","receiver_country":"US","receiver_state":"CA","receiver_city":"CHULA
			// VISTA","receiver_address_line1":"168 PALOMAR
			// ST.","receiver_address_line2":null,"receiver_zipcode":"91911-3411","packages":[{"package_code":"LPK07094697551","17track_code":"EZEPK7094697551YQ","erp_oid":"DOME14578328T1265","logistics_code":"794631631221202011241938455355","logistics_company":"USPSL","width_report":"4.00","length_report":"4.00","height_report":"4.00","weight_report":"200.00","discount_freight_report":"4.82","po_no":null,"invoice_no":null,"department_no":null,"error":null,"status":"4","status_label":"已就绪","status_lgs":null,"status_lgs_label":false,"cancel_status":null,"cancel_status_label":"未取消","scan_status":0,"scan_status_label":"未知","scanned_time":0,"refund_status":"无"}]}}
			if (null == httpClientResult) {
				return null;
			}
			String responseJson = httpClientResult.getContent();
			if (StringUtils.isBlank(responseJson)) {
				return null;
			}
			LOGGER.info("owdiex.detail.response.json:{}", responseJson);
			Map<String, Object> resultMap = new Gson().fromJson(responseJson, new TypeToken<Map<String, Object>>() {
			}.getType());
			Integer code = Double.valueOf(resultMap.get("code").toString()).intValue();
			if (code != 0) {
				return null;
			}
			@SuppressWarnings("unchecked")
			Map<String, Object> dataMap = (Map<String, Object>) resultMap.get("data");
			if (MapUtils.isEmpty(dataMap)) {
				return null;
			}
			@SuppressWarnings("unchecked")
			List<Map<String, Object>> packages = (List<Map<String, Object>>) dataMap.get("packages");
			if (CollectionUtils.isEmpty(packages)) {
				return null;
			}
			return (String) packages.get(0).get("logistics_code");
		} catch (Exception e) {
			LOGGER.error("owdiex.detail.request.exception:", e);
			return null;
		}
	}

	@Override
	public ApiLabelResponse label(String trackNumber, Map<String, String> configure) {
		return null;
	}

	@Override
	public ApiLabelResponse label(String referenceNo, String trackNumber, Map<String, String> configure) {
		String appKey = configure.get(ApiCredential.OWDIEX_APP_KEY.getKey());
		String appSecret = configure.get(ApiCredential.OWDIEX_APP_SECRET.getKey());
		String signBody = "appkey=" + appKey + "&order_code=" + referenceNo + appSecret;
		String sign = new MD5(signBody).toMD5();
		LOGGER.info("owdiex.label.request.sign:{}", sign);
		Map<String, String> headers = new HashMap<String, String>();
		headers.put("Content-Type", "application/x-www-form-urlencoded");
		Map<String, String> params = new LinkedHashMap<String, String>();
		params.put("appkey", appKey);
		params.put("order_code", referenceNo);
		params.put("sign", sign);
		try {
			HttpClientResult httpClientResult = HttpClientPoolUtil.doPost(PRINT, headers, params, false);
			String responseJson = httpClientResult.getContent();
			Map<String, Object> resultMap = new Gson().fromJson(responseJson, new TypeToken<Map<String, Object>>() {
			}.getType());
			@SuppressWarnings("unchecked")
			Map<String, Object> dataMap = (Map<String, Object>) resultMap.get("data");
			String label_contents = (String) dataMap.get("label_content");
			label_contents = label_contents.substring(2, label_contents.length() - 2);

			String pdfName = trackNumber + LabelSuffix.PDF.getSuffix();
			// 当前月份
			String centrePath = ApiUtil.getCurrentDay() + File.separator;
			String relativePath = DEFAULT_LABEL_FOLDER + File.separator + centrePath;
			String folderPath = DEFAULT_LABEL_ROOT + relativePath;
			if (!new File(folderPath).exists()) {
				new File(folderPath).mkdirs();
			}
			String fileUrl = folderPath + pdfName;
			try {
				// TODO 该base64解密方法需要重写
				ApiUtil.decoderBase64File(label_contents, fileUrl);
			} catch (Exception e) {
				LOGGER.error("owdiex.decode.file.exception", e);
			}
			ApiLabelResponse apiLabelResponse = new ApiLabelResponse();
			apiLabelResponse.setBarCode(trackNumber);
			apiLabelResponse.setLabelPath(relativePath + pdfName);
			return apiLabelResponse;
		} catch (Exception e) {
			LOGGER.error("owdiex.download.request.exception:", e);
			return new ApiLabelResponse(trackNumber, null);
		}
	}

	@Override
	public ApiLabelResponse labelRender(String trackNumber, ExpressOrderApi expressOrderApi) {
		return null;
	}

	@Override
	public void tracking(String trackNumber, Map<String, String> configure) {
	}

	@Override
	public String trackNumber(String code, Map<String, String> configure) {
		return null;
	}
}